package com.github.glomadrian.materialanimatedswitch.painter;

import com.github.glomadrian.materialanimatedswitch.MaterialAnimatedSwitchState;
import com.github.glomadrian.materialanimatedswitch.observer.BallFinishObservable;
import com.github.glomadrian.materialanimatedswitch.utils.AnimatorValueUtils;
import com.github.glomadrian.materialanimatedswitch.utils.Utils;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.app.Context;
import ohos.media.image.PixelMap;

import java.util.Observable;
import java.util.Observer;

public class IconReleasePainter extends IconPainter {
    private AnimatorValue enterXAnimator;
    private AnimatorValue enterYAnimator;
    private AnimatorValue exitXAnimator;
    private AnimatorValue exitYAnimator;
    private AnimatorValue exitAlphaAnimator;
    private int enterYAnimationStart;
    private int exitYAnimatorFinish;
    private int exitXAnimationStart;
    private BallFinishObservable ballFinishObservable;
    private MaterialAnimatedSwitchState actualState;
    private int iconMargin;
    private int middle;
    private boolean isAlphaEnterTrigger = false;

    public IconReleasePainter(Context context, PixelMap bitmap,
                              BallFinishObservable ballFinishObservable, int margin) {
        super(context, bitmap, margin);
        initValueAnimator();
        this.ballFinishObservable = ballFinishObservable;
        initObserver();
    }

    @Override
    protected void initBitmap() {
        super.initBitmap();
    }

    private void initValueAnimator() {
        int movementAnimationDuration = 400;
        int alphaAnimationDuration = 200;
        int curveCompensation = 14;

        enterXAnimator = new AnimatorValue();
        enterXAnimator.setDuration(movementAnimationDuration);
        enterXAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                int value = (int) AnimatorValueUtils.getAnimatedValue(v, width, 0);
                iconXPosition = value - iconMargin + margin;
            }
        });

        exitXAnimator = new AnimatorValue();
        exitXAnimator.setDuration(movementAnimationDuration);
        exitXAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                int value = (int) AnimatorValueUtils
                        .getAnimatedValue(v, 0, exitXAnimationStart);
                iconXPosition = value - iconMargin + margin;
            }
        });

        enterYAnimator = new AnimatorValue();
        enterYAnimator.setDuration(movementAnimationDuration - curveCompensation);
        enterYAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                int value = (int) AnimatorValueUtils.getAnimatedValue(v, enterYAnimationStart, middle);
                iconYPosition = value - iconMargin;
                if (v >= 0.5
                        && !isAlphaEnterTrigger
                        && actualState.equals(MaterialAnimatedSwitchState.RELEASE)) {
                    exitAlphaAnimator.start();
                    isAlphaEnterTrigger = true;
                }
            }
        });

        exitYAnimator = new AnimatorValue();
        exitYAnimator.setDuration(movementAnimationDuration);
        exitYAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                int value = (int) AnimatorValueUtils.getAnimatedValue(v, middle, exitYAnimatorFinish);
                iconYPosition = (value - iconMargin);
            }
        });

        exitAlphaAnimator = new AnimatorValue();
        exitAlphaAnimator.setDuration(alphaAnimationDuration);
        exitAlphaAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float value) {
                float uploadValue = value;
                if (actualState.equals(MaterialAnimatedSwitchState.PRESS)) {
                    uploadValue = 1f - value;
                }
                paint.setAlpha(uploadValue);
            }
        });
        exitAlphaAnimator.setStateChangedListener(new AlphaAnimatorStateListener());
    }

    @Override
    public int getColor() {
        return 0;
    }

    @Override
    public void setColor(int color) {
    }

    @Override
    public void setState(MaterialAnimatedSwitchState state) {
        this.actualState = state;
        switch (state) {
            case INIT:
                isVisible = true;
                break;
            case PRESS:
                exitYAnimator.start();
                exitXAnimator.start();
                exitAlphaAnimator.start();
                break;
            case RELEASE:
                isVisible = true;
                enterXAnimator.start();
                enterYAnimator.start();
                break;
            default:
                break;
        }
    }

    private void initObserver() {
        ballFinishObservable.addObserver(new BallFinishListener());
    }

    @Override
    public void onSizeChanged(int height, int width) {
        super.onSizeChanged(height, width);
        initValues();
        initAnimationsValues();
        iconYPosition = middle - (iconMargin);
        iconXPosition = margin - iconMargin;
    }

    private void initValues() {
        iconMargin = imageWidth / 2;
        middle = height / 2;
    }

    private void initAnimationsValues() {
        exitXAnimationStart = -Utils.vp2px(context, 15);
        exitYAnimatorFinish = Utils.vp2px(context, 34);
        enterYAnimationStart = -Utils.vp2px(context, 30);
    }

    private class BallFinishListener implements Observer {
        @Override
        public void update(Observable observable, Object data) {
            BallFinishObservable.BallState ballState =
                    ((BallFinishObservable) observable).getState();
            switch (ballState) {
                case PRESS:
                    isVisible = false;
                    break;
                default:
                    break;
            }
        }
    }

    private class AlphaAnimatorUpdateListener implements AnimatorValue.ValueUpdateListener {
        @Override
        public void onUpdate(AnimatorValue animatorValue, float v) {
            paint.setAlpha(v);
        }
    }

    private class AlphaAnimatorStateListener implements Animator.StateChangedListener {
        @Override
        public void onStart(Animator animator) {
        }

        @Override
        public void onStop(Animator animator) {
        }

        @Override
        public void onCancel(Animator animator) {
        }

        @Override
        public void onEnd(Animator animator) {
            isAlphaEnterTrigger = false;
        }

        @Override
        public void onPause(Animator animator) {
        }

        @Override
        public void onResume(Animator animator) {
        }
    }
}
